#include <LibraryConfig.hpp>

#ifdef ZZZ_LIB_FREEIMAGE
#include "Image.hpp"
#include "ImageHelper.hpp"
#include <FreeImage.h>

namespace zzz{
//NOT WORKING YET
//DONT KNOW HOW TO CONVERT ANY IMAGE TO RGBA
FIBITMAP *LoadImage(const string &filename)
{
  FIBITMAP *bitmap;
  FREE_IMAGE_FORMAT fif = FIF_UNKNOWN;
  // check the file signature and get its format
  // (the second argument is currently not used by FreeImage)
  fif = FreeImage_GetFileType(filename, 0);
  if(fif == FIF_UNKNOWN) {
    // no signature ?
    // try to guess the file format from the file extension
    fif = FreeImage_GetFIFFromFilename(filename);
  }
  // check that the plugin has reading capabilities ...
  if((fif != FIF_UNKNOWN) && FreeImage_FIFSupportsReading(fif)) {
    // Load the file
    bitmap = FreeImage_Load(fif, filename, 0);
  }
  return bitmap;
}

bool SaveImage(FIBITMAP *bitmap, const string &filename)
{
  FREE_IMAGE_FORMAT fif = FIF_UNKNOWN;
  BOOL bSuccess = FALSE;

  // Try to guess the file format from the file extension
  fif = FreeImage_GetFIFFromFilename(filename);
  if(fif != FIF_UNKNOWN) {
    // Check that the dib can be saved in this format
    BOOL bCanSave;

    FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(bitmap);
    if(image_type == FIT_BITMAP) {
      // standard bitmap type
      WORD bpp = FreeImage_GetBPP(bitmap);
      bCanSave = (FreeImage_FIFSupportsWriting(fif) && FreeImage_FIFSupportsExportBPP(fif, bpp));
    } else {
      // special bitmap type
      bCanSave = FreeImage_FIFSupportsExportType(fif, image_type);
    }

    if(bCanSave) {
      bSuccess = FreeImage_Save(fif, bitmap, filename, 0);
      return bSuccess==TRUE;
    }
  }
  return bSuccess==TRUE;
}

template<typename T>
void ConvertFrom(FIBITMAP *dib, Image<T> &dst)
{
  const FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib);
  const FREE_IMAGE_COLOR_TYPE image_color = FreeImage_GetColorType(dib);
  zuint height = FreeImage_GetHeight(dib);
  zuint width = FreeImage_GetWidth(dib);
  zsize size_all = height * width;

  switch(image_type)
  {
  case FIT_BITMAP:
    if (image_color == FIC_RGB)
    {
      Image<Vector3uc> img(height, width);
      memcpy(img.Data(), FreeImage_GetBits(dib), sizeof(Vector3uc)*size_all);
      ConvertImage<T, Vector3uc>(img, dst);
    }
    else if (image_color == FIC_RGBALPHA)
    {
      Image<Vector4uc> img(height, width);
      memcpy(img.Data(), FreeImage_GetBits(dib), sizeof(Vector3uc)*size_all);
      ConvertImage<T, Vector4uc>(img, dst);
    }
    break;
  }
}

#define IMAGE_SPECIALIZE(T) \
bool Image<T>::LoadFile(const string &filename)\
{\
  FIBITMAP *image=LoadImage(filename); \
  ConvertFrom(image, *this); \
  FreeImage_Unload(image); \
  return true; \
}\
bool Image<T>::SaveFile(const string &filename)\
{\
  FIBITMAP *image=FreeImage_Allocate(\
            Cols(),Rows(),sizeof(T),\
            FI_RGBA_RED_MASK,FI_RGBA_GREEN_MASK,FI_RGBA_BLUE_MASK); \
  memcpy(FreeImage_GetBits(image),v,sizeof(T)*size_all); \
  SaveImage(image,filename); \
  FreeImage_Unload(image); \
  return true; \
}\
;
IMAGE_SPECIALIZE(Vector4f);
IMAGE_SPECIALIZE(Vector3f);
IMAGE_SPECIALIZE(Vector4uc);
IMAGE_SPECIALIZE(Vector3uc);
IMAGE_SPECIALIZE(float);
IMAGE_SPECIALIZE(zuchar);
#undef IMAGE_SPECIALIZE
} // namespace zzz
#endif // ZZZ_LIB_FREEIMAGE
